/**
 * Copyright 2013 ABSir's Studio
 * 
 * All right reserved
 *
 * Create on 2013-6-17 上午11:14:11
 */
package com.absir.bean.core;

import java.lang.reflect.Method;

import com.absir.bean.basis.BeanDefine;
import com.absir.bean.basis.BeanFactory;
import com.absir.bean.basis.BeanScope;
import com.absir.core.kernel.KernelLang.CauseRuntimeException;
import com.absir.core.kernel.KernelString;

/**
 * @author absir
 * 
 */
public class BeanDefineMethod extends BeanDefineAbstract {

	/** beanDefine */
	protected BeanDefine beanDefine;

	/** method */
	Method method;

	/** paramNames */
	String[] paramNames;

	/**
	 * @param beanName
	 * @param method
	 * @return
	 */
	public static String getBeanName(String beanName, Method method) {
		if (KernelString.isEmpty(beanName)) {
			beanName = method.getName();
			if (beanName.startsWith("get")) {
				beanName = KernelString.uncapitalize(beanName.substring(3));
			}
		}

		return beanName;
	}

	/**
	 * @param method
	 * @return
	 */
	public static String[] getBeanParamNames(Method method) {
		if (method.getParameterTypes().length == 0) {
			return null;
		}

		return BeanDefineAbstract.getBeanParamNames(method.getParameterAnnotations());
	}

	/**
	 * @param beanFactory
	 * @param beanObject
	 * @param method
	 * @param paramNames
	 * @param required
	 * @return
	 */
	public static Object getBeanObject(BeanFactory beanFactory, Object beanObject, Method method, String[] paramNames,
			boolean required) {
		return getBeanObject(beanFactory, beanObject, method, paramNames, required, false);
	}

	/**
	 * @param beanFactory
	 * @param beanObject
	 * @param method
	 * @param paramNames
	 * @param required
	 * @param invoke
	 * @return
	 */
	public static Object getBeanObject(BeanFactory beanFactory, Object beanObject, Method method, String[] paramNames,
			boolean required, boolean invoke) {
		try {
			if (paramNames == null) {
				return method.invoke(beanObject);
			}

			int length = paramNames.length;
			if (!invoke && length == 0) {
				invoke = true;
			}

			Object[] parameters = new Object[length];
			Class<?>[] parameterTypes = method.getParameterTypes();
			for (int i = 0; i < length; i++) {
				Object parameter = beanFactory.getBeanObject(paramNames[i], parameterTypes[i], true);
				if (parameter == null) {
					if (required) {
						throw new RuntimeException("can not inject " + method.getDeclaringClass() + ".method = "
								+ method + " parameters [" + i + "]");
					}

				} else {
					invoke = true;
					parameters[i] = parameter;
				}
			}

			return invoke ? method.invoke(beanObject, parameters) : null;

		} catch (Exception e) {
			throw new CauseRuntimeException(e);
		}
	}

	/**
	 * @param method
	 */
	public BeanDefineMethod(Method method) {
		this(null, method);
	}

	/**
	 * @param beanDefine
	 * @param method
	 */
	public BeanDefineMethod(BeanDefine beanDefine, Method method) {
		this(null, beanDefine, method);
	}

	/**
	 * @param beanName
	 * @param beanDefine
	 * @param method
	 */
	public BeanDefineMethod(String beanName, BeanDefine beanDefine, Method method) {
		this.beanName = getBeanName(beanName, method);
		this.beanDefine = beanDefine;
		this.method = method;
		this.paramNames = getBeanParamNames(method);
	}

	/**
	 * @return
	 */
	public BeanDefine getBeanDefine() {
		return beanDefine;
	}

	/**
	 * @param beanDefine
	 *            the beanDefine to set
	 */
	public void setBeanDefine(BeanDefine beanDefine) {
		this.beanDefine = beanDefine;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.absir.android.bean.value.IBeanDefine#getBeanType()
	 */
	@Override
	public Class<?> getBeanType() {
		// TODO Auto-generated method stub
		return method.getReturnType();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.absir.android.bean.value.IBeanDefine#getBeanName()
	 */
	@Override
	public String getBeanName() {
		// TODO Auto-generated method stub
		return beanName;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.absir.android.bean.value.IBeanDefine#getBeanObject()
	 */
	@Override
	public Object getBeanObject() {
		// TODO Auto-generated method stub
		return getBeanObject(beanDefine == null ? null : beanDefine.getBeanObject(), method, paramNames);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.absir.android.bean.value.IBeanDefine#getBeanScope()
	 */
	@Override
	public BeanScope getBeanScope() {
		// TODO Auto-generated method stub
		return BeanScope.PROTOTYPE;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.absir.android.bean.value.IBeanDefine#getBeanComponent()
	 */
	@Override
	public Object getBeanComponent() {
		// TODO Auto-generated method stub
		return method;
	}

	/**
	 * @param method
	 * @return
	 */
	protected Object getBeanObject(Method method) {
		return getBeanObject(null, method);
	}

	/**
	 * @param factory
	 * @param method
	 * @return
	 */
	protected Object getBeanObject(Object factory, Method method) {
		return getBeanObject(factory, method, getBeanParamNames(method));
	}

	/**
	 * @param factory
	 * @param method
	 * @param paramNames
	 * @return
	 */
	protected Object getBeanObject(Object factory, Method method, String[] paramNames) {
		return getBeanObject(getBeanFactory(), factory, method, paramNames, false);
	}
}
